﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Demos.Cons
{
    /// <summary>
    /// 比较同步/异步在高并发情况下的耗时差异
    /// 知识点：多线程、Stopwatch 类、闭包、HttpClient
    /// </summary>
    public class AsyncRequsetDemo
    {
        public static async Task DoRequest()
        {
            await BuildRequestTasks(false);
            await BuildRequestTasks(true);
            Console.ReadKey();
        }
        /// <summary>
        /// 构建并发请求（模拟客户端的并发）
        /// </summary>
        /// <param name="isAsync">同步/异步</param>
        /// <returns></returns>
        static async Task BuildRequestTasks(bool isAsync)
        {
            List<Task> tasks = new List<Task>();
            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.Timeout = TimeSpan.FromMinutes(2);
                // 创建并启动计时器
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                for (int i = 0; i < 10; i++)
                {
                    //闭包
                    int requestId = i;
                    // 启动新的任务，并将其添加到任务列表中
                    tasks.Add(Task.Run(async () => await Request(httpClient, requestId, isAsync)));
                }
                // 等待所有任务完成
                await Task.WhenAll(tasks);
                // 停止计时器并记录总耗时
                stopwatch.Stop();
                Console.WriteLine($"All requests have completed in {stopwatch.Elapsed.TotalSeconds} seconds.");
                if (!isAsync)
                {
                    Console.WriteLine("注意：同步请求理论上应该是单个请求耗时*请求数，但因为web服务器拥有多线程处理机制，即使Thread.Sleep阻塞了当前线程，服务器也能分配新线程去处理其它请求，因此实际耗时会降低，但远不如异步");
                }
            }
        }

        /// <summary>
        /// 发起Http请求（服务端异步/同步）
        /// </summary>
        /// <param name="httpClient"></param>
        /// <param name="requestId"></param>
        /// <param name="isAsync"></param>
        /// <returns></returns>
        async static Task Request(HttpClient httpClient, int requestId, bool isAsync)
        {
            try
            {
                string msg = isAsync ? $"异步请求:Request {requestId} started." : $"同步请求:Request {requestId} started.";
                Console.WriteLine(msg);
                //LongTimeRequestAsync 异步Task.Delay；LongTimeRequest 同步Threed.Sleep
                string api = isAsync ? "http://192.168.1.55:9011/api/demo/LongTimeRequestAsync" : "http://192.168.1.55:9011/api/demo/LongTimeRequest";
                HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, api);
                var response = await httpClient.SendAsync(httpRequest);
                response.EnsureSuccessStatusCode();
                Console.WriteLine($"Request {requestId} succeeded.");
            }
            catch (OperationCanceledException ex)
            {
                Console.WriteLine($"Request {requestId} cancelled: {ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Request {requestId} error: {ex.Message}");
            }
        }
    }
}
